package worldofrobots;

import interfaces.MapPosition;

@SuppressWarnings("all")
public abstract class ReusableJoiningComp {
  @SuppressWarnings("all")
  public interface Requires {
    /**
     * This can be called by the implementation to access this required port.
     * 
     */
    public MapPosition allPositions();
  }
  
  
  @SuppressWarnings("all")
  public interface Provides {
  }
  
  
  @SuppressWarnings("all")
  public interface Component extends ReusableJoiningComp.Provides {
  }
  
  
  @SuppressWarnings("all")
  public interface Parts {
  }
  
  
  @SuppressWarnings("all")
  public static class ComponentImpl implements ReusableJoiningComp.Component, ReusableJoiningComp.Parts {
    private final ReusableJoiningComp.Requires bridge;
    
    private final ReusableJoiningComp implementation;
    
    public void start() {
      this.implementation.start();
      this.implementation.started = true;
      
    }
    
    protected void initParts() {
      
    }
    
    protected void initProvidedPorts() {
      
    }
    
    public ComponentImpl(final ReusableJoiningComp implem, final ReusableJoiningComp.Requires b, final boolean doInits) {
      this.bridge = b;
      this.implementation = implem;
      
      assert implem.selfComponent == null: "This is a bug.";
      implem.selfComponent = this;
      
      // prevent them to be called twice if we are in
      // a specialized component: only the last of the
      // hierarchy will call them after everything is initialised
      if (doInits) {
      	initParts();
      	initProvidedPorts();
      }
      
    }
  }
  
  
  @SuppressWarnings("all")
  public abstract static class JoiningEntity {
    @SuppressWarnings("all")
    public interface Requires {
    }
    
    
    @SuppressWarnings("all")
    public interface Provides {
      /**
       * This can be called to access the provided port.
       * 
       */
      public MapPosition positions();
    }
    
    
    @SuppressWarnings("all")
    public interface Component extends ReusableJoiningComp.JoiningEntity.Provides {
    }
    
    
    @SuppressWarnings("all")
    public interface Parts {
    }
    
    
    @SuppressWarnings("all")
    public static class ComponentImpl implements ReusableJoiningComp.JoiningEntity.Component, ReusableJoiningComp.JoiningEntity.Parts {
      private final ReusableJoiningComp.JoiningEntity.Requires bridge;
      
      private final ReusableJoiningComp.JoiningEntity implementation;
      
      public void start() {
        this.implementation.start();
        this.implementation.started = true;
        
      }
      
      protected void initParts() {
        
      }
      
      protected void initProvidedPorts() {
        assert this.positions == null: "This is a bug.";
        this.positions = this.implementation.make_positions();
        if (this.positions == null) {
        	throw new RuntimeException("make_positions() in worldofrobots.ReusableJoiningComp$JoiningEntity should not return null.");
        }
        
      }
      
      public ComponentImpl(final ReusableJoiningComp.JoiningEntity implem, final ReusableJoiningComp.JoiningEntity.Requires b, final boolean doInits) {
        this.bridge = b;
        this.implementation = implem;
        
        assert implem.selfComponent == null: "This is a bug.";
        implem.selfComponent = this;
        
        // prevent them to be called twice if we are in
        // a specialized component: only the last of the
        // hierarchy will call them after everything is initialised
        if (doInits) {
        	initParts();
        	initProvidedPorts();
        }
        
      }
      
      private MapPosition positions;
      
      public final MapPosition positions() {
        return this.positions;
      }
    }
    
    
    /**
     * Used to check that two components are not created from the same implementation,
     * that the component has been started to call requires(), provides() and parts()
     * and that the component is not started by hand.
     * 
     */
    private boolean init = false;;
    
    /**
     * Used to check that the component is not started by hand.
     */
    private boolean started = false;;
    
    private ReusableJoiningComp.JoiningEntity.ComponentImpl selfComponent;
    
    /**
     * Can be overridden by the implementation.
     * It will be called automatically after the component has been instantiated.
     * 
     */
    protected void start() {
      if (!this.init || this.started) {
      	throw new RuntimeException("start() should not be called by hand: to create a new component, use newComponent().");
      }
      
    }
    
    /**
     * This can be called by the implementation to access the provided ports.
     * 
     */
    protected ReusableJoiningComp.JoiningEntity.Provides provides() {
      assert this.selfComponent != null: "This is a bug.";
      if (!this.init) {
      	throw new RuntimeException("provides() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if provides() is needed to initialise the component.");
      }
      return this.selfComponent;
      
    }
    
    /**
     * This should be overridden by the implementation to define the provided port.
     * This will be called once during the construction of the component to initialize the port.
     * 
     */
    protected abstract MapPosition make_positions();
    
    /**
     * This can be called by the implementation to access the required ports.
     * 
     */
    protected ReusableJoiningComp.JoiningEntity.Requires requires() {
      assert this.selfComponent != null: "This is a bug.";
      if (!this.init) {
      	throw new RuntimeException("requires() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if requires() is needed to initialise the component.");
      }
      return this.selfComponent.bridge;
      
    }
    
    /**
     * This can be called by the implementation to access the parts and their provided ports.
     * 
     */
    protected ReusableJoiningComp.JoiningEntity.Parts parts() {
      assert this.selfComponent != null: "This is a bug.";
      if (!this.init) {
      	throw new RuntimeException("parts() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if parts() is needed to initialise the component.");
      }
      return this.selfComponent;
      
    }
    
    /**
     * Not meant to be used to manually instantiate components (except for testing).
     * 
     */
    public synchronized ReusableJoiningComp.JoiningEntity.Component _newComponent(final ReusableJoiningComp.JoiningEntity.Requires b, final boolean start) {
      if (this.init) {
      	throw new RuntimeException("This instance of JoiningEntity has already been used to create a component, use another one.");
      }
      this.init = true;
      ReusableJoiningComp.JoiningEntity.ComponentImpl comp = new ReusableJoiningComp.JoiningEntity.ComponentImpl(this, b, true);
      if (start) {
      	comp.start();
      }
      return comp;
      
    }
    
    private ReusableJoiningComp.ComponentImpl ecosystemComponent;
    
    /**
     * This can be called by the species implementation to access the provided ports of its ecosystem.
     * 
     */
    protected ReusableJoiningComp.Provides eco_provides() {
      assert this.ecosystemComponent != null: "This is a bug.";
      return this.ecosystemComponent;
      
    }
    
    /**
     * This can be called by the species implementation to access the required ports of its ecosystem.
     * 
     */
    protected ReusableJoiningComp.Requires eco_requires() {
      assert this.ecosystemComponent != null: "This is a bug.";
      return this.ecosystemComponent.bridge;
      
    }
    
    /**
     * This can be called by the species implementation to access the parts of its ecosystem and their provided ports.
     * 
     */
    protected ReusableJoiningComp.Parts eco_parts() {
      assert this.ecosystemComponent != null: "This is a bug.";
      return this.ecosystemComponent;
      
    }
  }
  
  
  /**
   * Used to check that two components are not created from the same implementation,
   * that the component has been started to call requires(), provides() and parts()
   * and that the component is not started by hand.
   * 
   */
  private boolean init = false;;
  
  /**
   * Used to check that the component is not started by hand.
   */
  private boolean started = false;;
  
  private ReusableJoiningComp.ComponentImpl selfComponent;
  
  /**
   * Can be overridden by the implementation.
   * It will be called automatically after the component has been instantiated.
   * 
   */
  protected void start() {
    if (!this.init || this.started) {
    	throw new RuntimeException("start() should not be called by hand: to create a new component, use newComponent().");
    }
    
  }
  
  /**
   * This can be called by the implementation to access the provided ports.
   * 
   */
  protected ReusableJoiningComp.Provides provides() {
    assert this.selfComponent != null: "This is a bug.";
    if (!this.init) {
    	throw new RuntimeException("provides() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if provides() is needed to initialise the component.");
    }
    return this.selfComponent;
    
  }
  
  /**
   * This can be called by the implementation to access the required ports.
   * 
   */
  protected ReusableJoiningComp.Requires requires() {
    assert this.selfComponent != null: "This is a bug.";
    if (!this.init) {
    	throw new RuntimeException("requires() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if requires() is needed to initialise the component.");
    }
    return this.selfComponent.bridge;
    
  }
  
  /**
   * This can be called by the implementation to access the parts and their provided ports.
   * 
   */
  protected ReusableJoiningComp.Parts parts() {
    assert this.selfComponent != null: "This is a bug.";
    if (!this.init) {
    	throw new RuntimeException("parts() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if parts() is needed to initialise the component.");
    }
    return this.selfComponent;
    
  }
  
  /**
   * Not meant to be used to manually instantiate components (except for testing).
   * 
   */
  public synchronized ReusableJoiningComp.Component _newComponent(final ReusableJoiningComp.Requires b, final boolean start) {
    if (this.init) {
    	throw new RuntimeException("This instance of ReusableJoiningComp has already been used to create a component, use another one.");
    }
    this.init = true;
    ReusableJoiningComp.ComponentImpl comp = new ReusableJoiningComp.ComponentImpl(this, b, true);
    if (start) {
    	comp.start();
    }
    return comp;
    
  }
  
  /**
   * This should be overridden by the implementation to instantiate the implementation of the species.
   * 
   */
  protected abstract ReusableJoiningComp.JoiningEntity make_JoiningEntity();
  
  /**
   * Do not call, used by generated code.
   * 
   */
  public ReusableJoiningComp.JoiningEntity _createImplementationOfJoiningEntity() {
    ReusableJoiningComp.JoiningEntity implem = make_JoiningEntity();
    if (implem == null) {
    	throw new RuntimeException("make_JoiningEntity() in worldofrobots.ReusableJoiningComp should not return null.");
    }
    assert implem.ecosystemComponent == null: "This is a bug.";
    assert this.selfComponent != null: "This is a bug.";
    implem.ecosystemComponent = this.selfComponent;
    return implem;
  }
  
  /**
   * This can be called to create an instance of the species from inside the implementation of the ecosystem.
   * 
   */
  protected ReusableJoiningComp.JoiningEntity.Component newJoiningEntity() {
    ReusableJoiningComp.JoiningEntity implem = _createImplementationOfJoiningEntity();
    return implem._newComponent(new ReusableJoiningComp.JoiningEntity.Requires() {},true);
  }
}
